package com.ruoyi.jihuo.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.jihuo.api.GetItemApi;
import com.ruoyi.jihuo.domain.JhTmGoods;
import com.ruoyi.jihuo.domain.JhTmProduct;
import com.ruoyi.jihuo.domain.JhTmUploadData;
import com.ruoyi.jihuo.domain.ProductWithGoods;
import com.ruoyi.jihuo.enums.JhTmUploadDataStatus;
import com.ruoyi.jihuo.mapper.JhTmUploadDataMapper;
import com.ruoyi.jihuo.service.IJhTmGoodsService;
import com.ruoyi.jihuo.service.IJhTmProductService;
import com.ruoyi.jihuo.service.IJhTmUploadDataService;
import com.ruoyi.jihuo.utils.MultipartFileUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * 数据包Service业务层处理
 *
 * @author ruoyi
 * @date 2025-03-27
 */
@Slf4j
@Service
public class JhTmUploadDataServiceImpl extends ServiceImpl<JhTmUploadDataMapper, JhTmUploadData> implements IJhTmUploadDataService {
    @Autowired
    private JhTmUploadDataMapper jhTmUploadDataMapper;

    @Autowired
    private GetItemApi getItemApi;

    @Autowired
    private IJhTmGoodsService jhTmGoodsService;

    @Autowired
    private IJhTmProductService jhTmProductService;

    @Autowired
    @Qualifier("uploadDataAnalysisExecutor")
    private ThreadPoolTaskExecutor uploadDataAnalysisExecutor;

    /**
     * 查询数据包
     *
     * @param jhId 数据包主键
     * @return 数据包
     */
    @Override
    public JhTmUploadData selectJhTmUploadDataByJhId(Long jhId) {
        return this.getById(jhId);
    }

    /**
     * 查询数据包列表
     *
     * @param jhTmUploadData 数据包
     * @return 数据包
     */
    @Override
    public List<JhTmUploadData> selectJhTmUploadDataList(JhTmUploadData jhTmUploadData) {
        return this.lambdaQuery()
                .eq(JhTmUploadData::getJhCreatedBy, SecurityUtils.getUsername())
                .orderByDesc(JhTmUploadData::getJhUpdatedTime)
                .list();
    }

    /**
     * 新增数据包
     * todo 插入前先根据itemId 查找，如果有就复制一份。如果数据太久了，则先删再插入
     * todo 如果后面重复数据很多可以考虑修改逻辑，货物中不存数据包，
     *
     * @param jhTmUploadData 数据包
     * @return 结果
     */
    @Override
//    @Transactional
    public String insertJhTmUploadData(JhTmUploadData jhTmUploadData, boolean isBatch) {
        jhTmUploadData.setJhNum(jhTmUploadData.getJhUrls().size());
        jhTmUploadData.setStatus(JhTmUploadDataStatus.PROCESSING.toString());
        jhTmUploadData.setJhDeleted("0");
        int row = jhTmUploadDataMapper.insert(jhTmUploadData);

        if (row > 0){
            //异步解析商品数据，不阻塞主线程执行结果
            List<String> productByGeMonths = jhTmProductService.getTmProductByGeMonths(4);
            Long userId = SecurityUtils.getUserId();
            CompletableFuture.runAsync(() -> packetParsing(jhTmUploadData, isBatch,productByGeMonths,userId), uploadDataAnalysisExecutor);
        }

        return String.valueOf(row);
    }

    public void packetParsing(JhTmUploadData jhTmUploadData, boolean isBatch, List<String> productByGeMonths, Long userId) {
        // 并发解析商品数据
        List<CompletableFuture<Optional<ProductWithGoods>>> futures = new ArrayList<>();
        // 使用线程安全的集合存储结果
        ConcurrentLinkedQueue<String> failUrls = new ConcurrentLinkedQueue<>();
        ConcurrentLinkedQueue<String> successUrls = new ConcurrentLinkedQueue<>();

        for (String url : jhTmUploadData.getJhUrls()) {
            String id = extractItemId(url);
            if (id == null) {
                if (!isBatch){
                    throw new RuntimeException("链接无法识别商品ID");
                }
                log.warn("链接无法识别商品ID，跳过：{}", url);
                failUrls.add(url);
                continue;
            }

            CompletableFuture<Optional<ProductWithGoods>> future = CompletableFuture.supplyAsync(() -> {
                try {
                    // 优化：每次任务中单独查询，避免线程安全问题
                    if (existsInRecentMonths(productByGeMonths, id)) {
                        log.info("商品 [{}] 在4个月内已采集，跳过", id);
                        List<JhTmProduct> products = jhTmProductService.likeJhUrlOrderByDesc(id);
                        JhTmProduct product = products.get(0);
                        product.setJhId(null);
                        product.setJhCreatedTime(null);
                        product.setJhUpdatedTime(null);
                        product.setJhDataId(String.valueOf(jhTmUploadData.getJhId()));
                        product.setJhUserId(userId);
                        String itemId = extractItemId(product.getJhUrl());
                        List<JhTmGoods> goods = jhTmGoodsService.selectJhTmGoodsByJhItemIdOrderByDesc(itemId);
                        JhTmGoods good = goods.get(0);
                        good.setJhId(null);
                        good.setJhUploadDataId(jhTmUploadData.getJhId());
                        good.setJhUpdatedTime(null);
                        good.setJhCreatedTime(null);
                        good.setJhOriginalUrl(url);
                        successUrls.add(url);
                        return Optional.of(new ProductWithGoods(good, product));
                    }

                    String itemJson = getItemApi.getItem("tmall", id);
                    JhTmGoods tempGoods = jhTmGoodsService.convertJsonToGoods(itemJson, jhTmUploadData.getJhId());
                    //基础的校验，校验不通过 抛出异常
                    fieldVerification(tempGoods);
                    if (tempGoods == null) return Optional.empty();
                    tempGoods.setJhOriginalUrl(url);
                    JhTmProduct product = new JhTmProduct();
                    product.setJhDataId(String.valueOf(jhTmUploadData.getJhId()));
                    product.setJhUrl(url);
                    product.setJhName(tempGoods.getJhTitle());
                    product.setJhClass(tempGoods.getJhCategoryId());
                    product.setJhPictureUrl(tempGoods.getJhCover());
                    product.setJhUserId(userId);
                    successUrls.add(url);
                    return Optional.of(new ProductWithGoods(tempGoods, product));
                } catch (Exception e) {
                    log.error("商品 [{}] 抓取失败: {}", id, e.getMessage(), e);
                    failUrls.add(url);
                    return Optional.empty();
                }
            }, uploadDataAnalysisExecutor);

            futures.add(future);
        }

        // 等待所有任务完成
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
        // 收集成功结果
        List<JhTmProduct> productList = new ArrayList<>();
        List<JhTmGoods> goodsList = new ArrayList<>();
        List<ProductWithGoods> dataList = new ArrayList<>();

        for (CompletableFuture<Optional<ProductWithGoods>> future : futures) {
            Optional<ProductWithGoods> optional = future.join();
            if (optional.isPresent()) {
                ProductWithGoods data = optional.get();
                goodsList.add(data.getGoods());
                dataList.add(data);
            }
        }

        // 批量插入
        boolean flag = jhTmGoodsService.saveBatch(goodsList,100);

        if (flag) {
            for (ProductWithGoods data : dataList) {
                productList.add(data.getProduct());
            }
        }

        // 批量插入产品
        if (!productList.isEmpty()) {
            jhTmProductService.saveBatch(productList);
        }

        jhTmUploadData.setJhId(jhTmUploadData.getJhId());
        jhTmUploadData.setStatus(JhTmUploadDataStatus.COMPLETED.toString());
        jhTmUploadData.setJhSuccessUrls(new ArrayList<>(successUrls));
        jhTmUploadData.setJhFailUrls(new ArrayList<>(failUrls));

        // 更新数据包表信息
        jhTmUploadDataMapper.updateById(jhTmUploadData);
    }

    private void fieldVerification(JhTmGoods tempGoods) {
        if (tempGoods.getJhCatProp() == null || tempGoods.getJhCatProp().isEmpty() ||
            ObjectUtils.isEmpty(tempGoods.getJhSkus()) ||
            ObjectUtils.isEmpty(tempGoods.getJhSaleProps())){
            throw new RuntimeException("商品基本信息为空");
        }
    }

    private static boolean existsInRecentMonths(List<String> productByGeMonths, String id) {
        return productByGeMonths.stream()
                .anyMatch(item -> item.contains("id=" + id));
    }

    /**
     * 提取ID
     * @param url
     * @return
     */
    private String extractItemId(String url) {
        try {
            String[] parts = url.split("id=");
            if (parts.length < 2) return null;
            return parts[1].split("&")[0];
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 修改数据包
     *
     * @param jhTmUploadData 数据包
     * @return 结果
     */
    @Override
    public int updateJhTmUploadData(JhTmUploadData jhTmUploadData) {
        return jhTmUploadDataMapper.updateJhTmUploadData(jhTmUploadData);
    }

    /**
     * 批量删除数据包
     *
     * @param jhIds 需要删除的数据包主键
     * @return 结果
     */
    @Override
    public int deleteJhTmUploadDataByJhIds(Long[] jhIds) {
        return jhTmUploadDataMapper.deleteBatchIds(Arrays.asList(jhIds));
    }

    /**
     * 删除数据包信息
     *
     * @param jhId 数据包主键
     * @return 结果
     */
    @Override
    public int deleteJhTmUploadDataByJhId(Long jhId) {
        return jhTmUploadDataMapper.deleteJhTmUploadDataByJhId(jhId);
    }

    /**
     * 导入数据包
     * @param file 导入文件
     * @return 结果
     */
    @Override
    public String importData(MultipartFile file) {
        String originalName = file.getOriginalFilename();
        String fileName = null;
        if (originalName != null && originalName.contains(".")) {
            fileName = originalName.substring(0, originalName.lastIndexOf('.'));
        }

        List<String> urls = MultipartFileUtils.readTxtToList(file);
        JhTmUploadData jhTmUploadData = new JhTmUploadData();
        jhTmUploadData.setJhDataName(fileName);
        jhTmUploadData.setJhNum(urls.size());
        jhTmUploadData.setJhUrls(urls);
        return this.insertJhTmUploadData(jhTmUploadData, true);
    }
}
